<template>
  <div class="grid-image-cutter">
    <div class="container">
      <h1>九宫格/多格切图</h1>
      <div class="image-preview">
        <img :src="imageUrl" alt="预览图" @load="onImageLoad" v-if="imageUrl">
        <div class="upload-hint" v-else @click="uploadImage">
          <el-icon :size="40"><Plus /></el-icon>
          <p>点击上传图片</p>
        </div>
        <div class="grid-lines" v-if="imageUrl">
          <div v-for="line in gridLines" :key="line.id" :class="line.class" :style="line.style"></div>
        </div>
      </div>
      <div class="control-panel">
        <el-radio-group v-model="gridType">
          <el-radio-button value="equal">输入行列均分切图</el-radio-button>
          <el-radio-button value="auto">输入宽高自动切图</el-radio-button>
        </el-radio-group>
        <template v-if="gridType === 'equal'">
          <el-input-number v-model="rows" :min="1" :max="10" placeholder="行数"></el-input-number>
          <el-input-number v-model="cols" :min="1" :max="10" placeholder="列数"></el-input-number>
        </template>
        <template v-else>
          <el-input-number v-model="gridWidth" :min="50" :max="1000" placeholder="宽度"></el-input-number>
          <el-input-number v-model="gridHeight" :min="50" :max="1000" placeholder="高度"></el-input-number>
        </template>
      </div>
      <el-button type="primary" @click="cutImage" :disabled="!imageUrl" class="cut-button">
        <el-icon><Crop /></el-icon>
        开始切图
      </el-button>
      <div class="button-group">
        <el-button type="success" @click="uploadImage">
          <el-icon><Upload /></el-icon>
          上传
        </el-button>
        <el-button type="primary" @click="downloadAll" :disabled="gridImages.length === 0">
          <el-icon><Download /></el-icon>
          打包下载
        </el-button>
        <el-button type="warning" @click="goToHomepage">
          <el-icon><Back /></el-icon>
          返回
        </el-button>
      </div>
      <input type="file" ref="fileInput" class="hidden-input" @change="handleFileChange" accept="image/*">
      <div class="tool-intro">
        <h3>工具介绍及使用方法：</h3>
        <ol>
          <li>本工具可以将单张切割为常用的九宫格照片或自定义多格照片。</li>
          <li>本工具有两种切割照片的模式，一种是指定行列均分切图式，一种为指定宽度与高度切割的方式。</li>
          <li>切割后的照片，可以一次性打包全部下载。</li>
          <li>本工具在浏览器中处理，你上传的照片不会上传至服务器，请放心使用。</li>
        </ol>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { Plus, Upload, Download, Back, Crop } from '@element-plus/icons-vue'
import JSZip from 'jszip'
import { saveAs } from 'file-saver'

const router = useRouter()
const fileInput = ref(null)
const imageUrl = ref('')
const gridType = ref('equal')
const rows = ref(3)
const cols = ref(3)
const gridWidth = ref(300)
const gridHeight = ref(300)
const gridImages = ref([])
const imageWidth = ref(0)
const imageHeight = ref(0)

const gridLines = computed(() => {
  const lines = []
  if (!imageUrl.value) return lines

  if (gridType.value === 'equal') {
    for (let i = 1; i < rows.value; i++) {
      lines.push({
        id: `h${i}`,
        class: 'grid-line grid-line-horizontal',
        style: { top: `${(i / rows.value) * 100}%` }
      })
    }
    for (let i = 1; i < cols.value; i++) {
      lines.push({
        id: `v${i}`,
        class: 'grid-line grid-line-vertical',
        style: { left: `${(i / cols.value) * 100}%` }
      })
    }
  } else {
    const horizontalLines = Math.floor(imageHeight.value / gridHeight.value)
    const verticalLines = Math.floor(imageWidth.value / gridWidth.value)
    for (let i = 1; i < horizontalLines; i++) {
      lines.push({
        id: `h${i}`,
        class: 'grid-line grid-line-horizontal',
        style: { top: `${(i * gridHeight.value / imageHeight.value) * 100}%` }
      })
    }
    for (let i = 1; i < verticalLines; i++) {
      lines.push({
        id: `v${i}`,
        class: 'grid-line grid-line-vertical',
        style: { left: `${(i * gridWidth.value / imageWidth.value) * 100}%` }
      })
    }
  }
  return lines
})

const handleFileChange = (event) => {
  const file = event.target.files[0]
  if (file) {
    const reader = new FileReader()
    reader.onload = (e) => {
      imageUrl.value = e.target.result
    }
    reader.readAsDataURL(file)
  }
}

const cutImage = () => {
  if (!imageUrl.value) {
    ElMessage.error('请先上传图片')
    return
  }

  const img = new Image()
  img.onload = () => {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    let width, height, r, c

    if (gridType.value === 'equal') {
      width = img.width / cols.value
      height = img.height / rows.value
      r = rows.value
      c = cols.value
    } else {
      width = gridWidth.value
      height = gridHeight.value
      r = Math.ceil(img.height / height)
      c = Math.ceil(img.width / width)
    }

    gridImages.value = []

    for (let i = 0; i < r; i++) {
      for (let j = 0; j < c; j++) {
        canvas.width = width
        canvas.height = height
        ctx.drawImage(img, j * width, i * height, width, height, 0, 0, width, height)
        gridImages.value.push(canvas.toDataURL())
      }
    }

    ElMessage.success('切图完成')
  }
  img.src = imageUrl.value
}

const uploadImage = () => {
  fileInput.value.click()
}

const downloadAll = () => {
  if (gridImages.value.length === 0) {
    ElMessage.error('请先进行切图')
    return
  }

  const zip = new JSZip()
  gridImages.value.forEach((dataUrl, index) => {
    const base64Data = dataUrl.replace(/^data:image\/\w+;base64,/, "")
    zip.file(`grid_${index + 1}.png`, base64Data, {base64: true})
  })

  zip.generateAsync({type:"blob"}).then((content) => {
    saveAs(content, "grid_images.zip")
  })
}

const onImageLoad = (event) => {
  imageWidth.value = event.target.naturalWidth
  imageHeight.value = event.target.naturalHeight
}

const goToHomepage = () => {
  router.push('/')
}
</script>

<style lang="scss" scoped>
.grid-image-cutter {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0 10px;

  .container {
    max-width: 1000px;
    width: 98%;
    background-color: rgba(255, 255, 255, 0.95);
    border-radius: 20px;
    box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
    padding: 25px;
    box-sizing: border-box;

    h1 {
      text-align: center;
      color: #4a5568;
      font-size: 2.5em;
      margin: 0 0 25px 0;
      text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
    }

    .image-preview {
      position: relative;
      width: 100%;
      min-height: 300px;
      border: 2px dashed #ddd;
      border-radius: 8px;
      overflow: hidden;
      background-color: #f8f9fa;
      margin-bottom: 20px;

      img {
        max-width: 100%;
        height: auto;
        display: block;
      }

      .upload-hint {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        text-align: center;
        color: #909399;
        cursor: pointer;

        p {
          margin: 10px 0 0;
          font-size: 14px;
        }
      }

      .grid-lines {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        pointer-events: none;

        .grid-line {
          position: absolute;
          background-color: rgba(255, 255, 255, 0.7);
          box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);

          &.grid-line-horizontal {
            left: 0;
            right: 0;
            height: 2px;
          }

          &.grid-line-vertical {
            top: 0;
            bottom: 0;
            width: 2px;
          }
        }
      }
    }

    .control-panel {
      background-color: #f8fafc;
      padding: 20px;
      border-radius: 12px;
      margin-bottom: 20px;
      display: flex;
      flex-wrap: wrap;
      gap: 15px;
      align-items: center;

      .el-radio-group {
        margin-right: 15px;
      }

      .el-input-number {
        width: 120px;
      }
    }

    .cut-button {
      width: 100%;
      margin-bottom: 20px;
      height: 40px;
      display: flex;
      align-items: center;
      justify-content: center;

      .el-icon {
        margin-right: 8px;
      }
    }

    .button-group {
      display: flex;
      justify-content: center;
      gap: 15px;
      margin-bottom: 20px;

      .el-button {
        min-width: 100px;
        display: flex;
        align-items: center;
        justify-content: center;

        .el-icon {
          margin-right: 6px;
        }

        &:hover {
          transform: translateY(-2px);
          box-shadow: 0 4px 12px rgba(0,0,0,0.1);
        }
      }
    }

    .tool-intro {
      background-color: #fdf6ec;
      border: 1px solid #faecd8;
      padding: 20px;
      border-radius: 10px;
      margin-top: 20px;
      text-align: left;

      h3 {
        margin: 0 0 15px 0;
        color: #e6a23c;
        font-size: 1.2em;
        text-align: left;
      }

      ol {
        margin: 0;
        padding-left: 20px;
        color: #606266;
        text-align: left;

        li {
          margin-bottom: 10px;
          line-height: 1.5;
          text-align: left;

          &:last-child {
            margin-bottom: 0;
          }
        }
      }
    }

    .hidden-input {
      display: none;
    }
  }
}

@media (max-width: 768px) {
  .grid-image-cutter {
    padding: 10px;

    .container {
      padding: 15px;

      h1 {
        font-size: 20px;
        margin-bottom: 15px;
      }

      .image-preview {
        min-height: 200px;
      }

      .control-panel {
        padding: 15px;
        flex-direction: column;
        align-items: stretch;

        .el-radio-group {
          margin-right: 0;
          margin-bottom: 10px;
        }

        .el-input-number {
          width: 100%;
        }
      }

      .button-group {
        flex-direction: column;
        gap: 10px;

        .el-button {
          width: 100%;
        }
      }

      .tool-intro {
        padding: 15px;

        h3 {
          font-size: 16px;
        }

        ol {
          font-size: 14px;
        }
      }
    }
  }
}
</style>
